import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
import { config } from '../config';

// 密码哈希
export const hashPassword = async (password: string): Promise<string> => {
  const saltRounds = 12;
  return bcrypt.hash(password, saltRounds);
};

// 密码验证
export const verifyPassword = async (password: string, hashedPassword: string): Promise<boolean> => {
  return bcrypt.compare(password, hashedPassword);
};

// 生成访问令牌
export const generateAccessToken = (payload: any): string => {
  return jwt.sign(payload, config.JWT_SECRET, {
    expiresIn: config.JWT_ACCESS_EXPIRES_IN || '24h'
  } as any);
};

// 生成刷新令牌
export const generateRefreshToken = (payload: any): string => {
  return jwt.sign(payload, config.JWT_SECRET, {
    expiresIn: config.JWT_REFRESH_EXPIRES_IN || '7d'
  } as any);
};

// 验证访问令牌
export const verifyAccessToken = (token: string): any => {
  try {
    return jwt.verify(token, config.JWT_SECRET);
  } catch (error) {
    throw new Error('Invalid access token');
  }
};

// 验证刷新令牌
export const verifyRefreshToken = (token: string): any => {
  try {
    return jwt.verify(token, config.JWT_SECRET);
  } catch (error) {
    throw new Error('Invalid refresh token');
  }
};

// 生成密码重置令牌
export const generatePasswordResetToken = (): string => {
  return crypto.randomBytes(32).toString('hex');
};

// 生成邮箱验证令牌
export const generateEmailVerificationToken = (): string => {
  return crypto.randomBytes(32).toString('hex');
};

// 生成双因素认证令牌
export const generateTwoFactorToken = (): string => {
  return crypto.randomBytes(16).toString('hex').substring(0, 6).toUpperCase();
};

// 生成API密钥
export const generateApiKey = (): string => {
  return `sk-${crypto.randomBytes(32).toString('hex')}`;
};

// 生成会话ID
export const generateSessionId = (): string => {
  return crypto.randomBytes(32).toString('hex');
};

// 检查密码强度
export const checkPasswordStrength = (password: string): {
  score: number;
  feedback: string[];
  isStrong: boolean;
} => {
  const feedback: string[] = [];
  let score = 0;

  // 长度检查
  if (password.length >= 8) {
    score += 1;
  } else {
    feedback.push('密码长度至少8个字符');
  }

  // 包含小写字母
  if (/[a-z]/.test(password)) {
    score += 1;
  } else {
    feedback.push('包含小写字母');
  }

  // 包含大写字母
  if (/[A-Z]/.test(password)) {
    score += 1;
  } else {
    feedback.push('包含大写字母');
  }

  // 包含数字
  if (/\d/.test(password)) {
    score += 1;
  } else {
    feedback.push('包含数字');
  }

  // 包含特殊字符
  if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) {
    score += 1;
  } else {
    feedback.push('包含特殊字符');
  }

  // 检查常见弱密码
  const commonPasswords = [
    'password', '123456', '123456789', 'qwerty', 'abc123',
    'password123', 'admin', 'letmein', 'welcome', 'monkey'
  ];

  if (commonPasswords.includes(password.toLowerCase())) {
    score -= 2;
    feedback.push('避免使用常见密码');
  }

  // 检查重复字符
  if (/(.)\1{2,}/.test(password)) {
    score -= 1;
    feedback.push('避免重复字符');
  }

  // 检查连续字符
  if (/abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz/i.test(password)) {
    score -= 1;
    feedback.push('避免连续字符');
  }

  const isStrong = score >= 4;

  return {
    score: Math.max(0, score),
    feedback,
    isStrong
  };
};

// 生成安全的随机密码
export const generateSecurePassword = (length: number = 16): string => {
  const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';
  let password = '';

  // 确保至少包含每种字符类型
  password += 'abcdefghijklmnopqrstuvwxyz'[Math.floor(Math.random() * 26)]; // 小写字母
  password += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[Math.floor(Math.random() * 26)]; // 大写字母
  password += '0123456789'[Math.floor(Math.random() * 10)]; // 数字
  password += '!@#$%^&*()_+-=[]{}|;:,.<>?'[Math.floor(Math.random() * 32)]; // 特殊字符

  // 填充剩余长度
  for (let i = 4; i < length; i++) {
    password += charset[Math.floor(Math.random() * charset.length)];
  }

  // 打乱密码字符顺序
  return password.split('').sort(() => Math.random() - 0.5).join('');
};

// 生成OTP（一次性密码）
export const generateOTP = (length: number = 6): string => {
  const digits = '0123456789';
  let otp = '';
  
  for (let i = 0; i < length; i++) {
    otp += digits[Math.floor(Math.random() * 10)];
  }
  
  return otp;
};

// 生成TOTP密钥（用于Google Authenticator等）
export const generateTOTPSecret = (): string => {
  return crypto.randomBytes(20).toString('base64');
};

// 验证TOTP令牌
export const verifyTOTP = (token: string, secret: string, window: number = 1): boolean => {
  // 这里应该使用真实的TOTP库，如speakeasy
  // 这是一个简化的实现
  try {
    const currentTime = Math.floor(Date.now() / 30000); // 30秒窗口
    
    for (let i = -window; i <= window; i++) {
      const time = currentTime + i;
      const expectedToken = generateTOTPForTime(secret, time);
      if (token === expectedToken) {
        return true;
      }
    }
    
    return false;
  } catch (error) {
    return false;
  }
};

// 为特定时间生成TOTP（简化实现）
const generateTOTPForTime = (secret: string, time: number): string => {
  // 这是一个简化的实现，实际应该使用speakeasy库
  const hash = crypto.createHmac('sha1', secret)
    .update(time.toString())
    .digest('hex');
  
  const offset = parseInt(hash.slice(-1), 16);
  const code = parseInt(hash.slice(offset, offset + 6), 16) % 1000000;
  
  return code.toString().padStart(6, '0');
};

// 生成安全的随机盐值
export const generateSalt = (length: number = 16): string => {
  return crypto.randomBytes(length).toString('hex');
};

// 生成安全的随机IV（初始化向量）
export const generateIV = (): Buffer => {
  return crypto.randomBytes(16);
};

// 加密敏感数据
export const encryptData = (data: string, key: string): string => {
  const iv = generateIV();
  const cipher = crypto.createCipher('aes-256-cbc', key);
  
  let encrypted = cipher.update(data, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  return iv.toString('hex') + ':' + encrypted;
};

// 解密敏感数据
export const decryptData = (encryptedData: string, key: string): string => {
  const parts = encryptedData.split(':');
  const iv = Buffer.from(parts[0], 'hex');
  const encrypted = parts[1];
  
  const decipher = crypto.createDecipher('aes-256-cbc', key);
  
  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  
  return decrypted;
};
